use pdata::internal::data::protogen::collector::logs::v1::{
    ExportLogsServiceRequest, logs_service_client::LogsServiceClient,
};
use pdata::internal::data::protogen::collector::metrics::v1::{
    ExportMetricsServiceRequest, metrics_service_client::MetricsServiceClient,
};
use pdata::internal::data::protogen::collector::trace::v1::{
    ExportTraceServiceRequest, trace_service_client::TraceServiceClient,
};
use tonic::transport::{Channel, Endpoint};

use crate::consumer::{ConsumeLogs, ConsumeMetrics, ConsumeTraces};

use std::sync::Arc;

/// OTLP gRPC exporter
/// - Use one tonic channel for traces, metrics and logs
/// - Intended to be shared via `Arc`
pub struct OtlpGrpcExporter {
    channel: Channel,
}

impl OtlpGrpcExporter {
    /// Create an exporter with a lazy gRPC channel
    ///
    /// * `destination` - The gRPC endpoint to connect to
    /// * `_use_tls` - Whether to use TLS (currently ignored)
    ///
    /// The channel will attempt to connect on first use and automatically reconnect.
    ///
    /// Use lazy connection so startup does not fail when the remote endpoint is unavailable.
    pub async fn connect(
        destination: String,
    ) -> Result<Arc<Self>, Box<dyn std::error::Error + Send + Sync>> {
        let endpoint = Endpoint::from_shared(destination)?;
        let channel = endpoint.connect_lazy();
        Ok(Arc::new(Self { channel }))
    }
}

#[tonic::async_trait]
impl ConsumeTraces for OtlpGrpcExporter {
    /// Export traces to the gRPC endpoint
    async fn consume(&self, data: ExportTraceServiceRequest) {
        let mut client = TraceServiceClient::new(self.channel.clone());
        let _ = client.export(data).await;
    }
}

#[tonic::async_trait]
impl ConsumeMetrics for OtlpGrpcExporter {
    /// Export metrics to the gRPC endpoint
    async fn consume(&self, data: ExportMetricsServiceRequest) {
        let mut client = MetricsServiceClient::new(self.channel.clone());
        let _ = client.export(data).await;
    }
}

#[tonic::async_trait]
impl ConsumeLogs for OtlpGrpcExporter {
    /// Export logs to the gRPC endpoint
    async fn consume(&self, data: ExportLogsServiceRequest) {
        let mut client = LogsServiceClient::new(self.channel.clone());
        let _ = client.export(data).await;
    }
}
